#include "wifi_adapter.h"
#include "wifi_device.h"
#include "wifi_hotspot_config.h"
#include "iot_uart.h"
#include "stdint.h"
#include "string.h"
#include "los_list.h"
#include "stm32f4xx_ll_usart.h"
#include "stm32f4xx_ll_bus.h"
#include "queue.h"
#include "ll_gpio.h"
#include "ll_uart.h"

/*
AT version:1.3.0.0(Jul 14 2016 18:54:01)
SDK version:2.0.0(656edbf)
compile time:Jul 19 2016 18:44:44
OK

WIFI DISCONNECT

WIFI CONNECTED
WIFI GOT IP

+STA_CONNECTED:"f2:bd:c0:a9:b0:37"
+DIST_STA_IP:"f2:bd:c0:a9:b0:37","192.168.4.2"

+STA_DISCONNECTED:"f2:bd:c0:a9:b0:37"
*/


extern uint8_t g_uartRxBuffer_1[UART1_RX_LEN];
extern uint8_t g_uartRxBuffer_2[UART2_RX_LEN];
extern uint8_t g_uartRxBuffer_3[UART3_RX_LEN];
extern uint8_t g_uartRxBuffer_4[UART4_RX_LEN];
extern uint8_t g_uartRxBuffer_5[UART5_RX_LEN];
extern uint8_t g_uartRxBuffer_6[UART6_RX_LEN];
extern UART_Config g_uartConfig[UART_MAX];
extern QueueInfo g_queueInfo[QUEUE_MAX];
extern uint8_t g_clientQueue;
extern unsigned char g_scanQueue;
char g_atRecvBuf[100];
uint16_t g_atLen;
uint8_t g_listenWiFi;
static char rsp_buf[1024] = {0};
uint8_t g_ESP8266_MsgQueue = 0xff;

// 字符串mac转为6个hex
void mac_str2hex(unsigned char *dst, char *src)
{
    int i;
    char tmp[2];
    for (i = 0; i < 6; i++)
    {
        memcpy(tmp, &src[i * 3], 2);
        for (int j = 0; j < 2; j++)
        {
            // 大写转小写
            if (tmp[j] >= 'A' && tmp[j] <= 'Z')
                tmp[j] = tolower(tmp[j]);
            // 字符转数字
            if (tmp[j] >= '0' && tmp[j] <= '9')
                tmp[j] = tmp[j] - '0';
            else if (tmp[j] >= 'a' && tmp[j] <= 'z')
                tmp[j] = tmp[j] - 87;
        }
        dst[i] = tmp[0] * 16 + tmp[1];
    }
}
// hex数组转为mac字符串
void mac_hex2str(unsigned char *dst, unsigned char *src)
{
    int i;
    for (i = 0; i < 6; i++)
    {
        sprintf(dst + i * 3, "%02x", src[i]);
        if (i != 0)
            dst[i * 3 - 1] = ':';
    }
}
// 字符串ip转为整数
uint32_t ip_to_int(char *ip)
{
    uint32_t result = 0;
    char a[4] = {0};
    char b[4] = {0};
    char c[4] = {0};
    char d[4] = {0};
    int i, l = 0, m = 0, n = 0;
    for (i = 0; i < strlen(ip); i++)
    {
        if (ip[i] == '.')
        {
            if (l == 0)
                l = i;
            else if (m == 0)
                m = i;
            else if (n == 0)
                n = i;
        }
    }
    memcpy(a, ip, l);
    memcpy(b, ip + l + 1, m - l - 1);
    memcpy(c, ip + m + 1, n - m - 1);
    memcpy(d, ip + n + 1, strlen(ip) - n - 1);
    return ((unsigned int)atoi(a) << 24) + ((unsigned int)atoi(b) << 16) + ((unsigned int)atoi(c) << 8) + atoi(d);
}
// 整数ip转为字符串
void int_to_ip(char *ip_str, uint32_t ip_int)
{
    sprintf(ip_str, "%d.%d.%d.%d", (ip_int >> 24) & 0xff, (ip_int >> 16) & 0xff, (ip_int >> 8) & 0xff, (ip_int >> 0) & 0xff);
}

unsigned int ChannelToFrequency(unsigned int channel)
{
    if (channel <= 0){
        return 0;
    }
    if (channel == CHANNEL_80211B_ONLY){
        return FREQ_OF_CHANNEL_80211B_ONLY;
    }
    return (((channel - WIFI_MIN_CHANNEL) * WIFI_FREQ_INTERVAL) + FREQ_OF_CHANNEL_1);
}
unsigned int FrequencyToChannel(unsigned int frequency)
{
    if (frequency == FREQ_OF_CHANNEL_80211B_ONLY){
        return CHANNEL_80211B_ONLY;
    }
    if (frequency < FREQ_OF_CHANNEL_1){
        return 0;
    }
    return (frequency - FREQ_OF_CHANNEL_1) / WIFI_FREQ_INTERVAL + WIFI_MIN_CHANNEL;
}

void PrintScanInfo(WifiScanInfo *info)
{
    if(info == NULL)
        return;
    char mac[18]={0};
    mac_hex2str(mac, info->bssid);
    printf("Hotspot : %s,%s,%d,%d,%d\n", info->ssid, mac, info->securityType, info->rssi, info->frequency);
}
void PrintWifiError(WifiErrorCode res)
{
    switch(res)
    {
        case WIFI_SUCCESS: printf("\bSuccess ...\n"); break;
        case ERROR_WIFI_INVALID_ARGS: printf("Failed, reason is : ERROR_WIFI_INVALID_ARGS\n"); break;
        case ERROR_WIFI_CHIP_INVALID: printf("Failed, reason is : ERROR_WIFI_CHIP_INVALID\n"); break;
        case ERROR_WIFI_IFACE_INVALID: printf("Failed, reason is : ERROR_WIFI_IFACE_INVALID\n"); break;
        case ERROR_WIFI_RTT_CONTROLLER_INVALID: printf("Failed reason is : ERROR_WIFI_RTT_CONTROLLER_INVALID\n"); break;
        case ERROR_WIFI_NOT_SUPPORTED: printf("Failed, reason is : ERROR_WIFI_NOT_SUPPORTED\n"); break;
        case ERROR_WIFI_NOT_AVAILABLE: printf("Failed, reason is : ERROR_WIFI_NOT_AVAILABLE\n"); break;
        case ERROR_WIFI_NOT_STARTED: printf("Failed, reason is : ERROR_WIFI_NOT_STARTED\n"); break;
        case ERROR_WIFI_BUSY: printf("Failed, reason is : ERROR_WIFI_BUSY\n"); break;
        case ERROR_WIFI_INVALID_PASSWORD: printf("Failed, reason is : ERROR_WIFI_INVALID_PASSWORD\n"); break;
        case ERROR_WIFI_UNKNOWN: printf("Failed, reason is : ERROR_WIFI_UNKNOWN\n"); break;
        default: break;
    }
}

int WifiUartInit()
{
    WifiErrorCode res;
    // 初始化串口
    IotUartAttribute param;
    param.baudRate = 115200;
    param.dataBits = IOT_UART_DATA_BIT_8;
    param.parity = IOT_UART_PARITY_NONE;
    param.stopBits = IOT_UART_STOP_BIT_1;
    IoTUartInit(AT_USART_PORT, &param);
	// 发送指令
    SendWifiCommand(WIFI_RESET, NULL);
    res = WaitWifiResponse(WIFI_RESET, NULL, WIFI_TIMEOUT);
    return res;
}

// 字符串中有“ "\, ” 需要转义” \" \, \\“ 并且SSID和PASSWD都要被双引号包围
// a"b,c\d ---> "a\"b\,c\\d"
void ESP8266_GenerateSSIDAndPassword(char *dst, char *src)
{
    uint8_t num = 1;
    uint8_t i;
    uint8_t len = strlen(src);

    if (dst == NULL)
        return FAILED;
    // 清空数据
    memset(dst, 0, strlen(dst));
    // 头部增加双引号
    dst[0] = '\"';
    for (i = 0; i < strlen(src); i++)
    {
        // 遇到 \," 进行转义
        if (src[i] == '\\' || src[i] == '\,' || src[i] == '\"')
        {
            dst[i + num] = '\\';
            num++;
        }
        dst[i + num] = src[i];
    }
    // 尾部增加双引号
    dst[i + num] = '\"';
    return SUCCESS;
}

// 解析扫描的热点数据
void ParseWifiScanResult(char *buf, WifiScanInfo *info)
{
    // 分割字符串
    char ecn[2]={0}, rssi[4]={0}, *ssid, mac[17]={0}, *channel[3]={0};
    // 加密方式
    char *tmp , *saveptr;
    tmp = strtok_r(buf, ",", &saveptr);
    if (tmp != NULL)
    {
        int tmp_len = strlen(tmp);
        memcpy(ecn, tmp, tmp_len);
        tmp = strtok_r(NULL, ",", &saveptr);
    }
    if (ecn[0] == 0)
        info->securityType = WIFI_SEC_TYPE_OPEN;
    else if (ecn[0] == 1)
        info->securityType = WIFI_SEC_TYPE_WEP;
    else if (ecn[0] == 2)
        info->securityType = WIFI_SEC_TYPE_PSK;
    else
        info->securityType = WIFI_SEC_TYPE_INVALID;
    // ssid
    if (tmp != NULL)
    {
        int tmp_len = strlen(tmp);
        memset(info->ssid, 0, WIFI_MAX_SSID_LEN);
        memcpy(info->ssid, tmp + 1, tmp_len - 2);
        tmp = strtok_r(NULL, ",", &saveptr);
    }
    // rssi
    if (tmp != NULL)
    {
        int tmp_len = strlen(tmp);
        memcpy(rssi, tmp, tmp_len);
        tmp = strtok_r(NULL, ",", &saveptr);
    }
    info->rssi = atoi(rssi);
    // mac
    if (tmp != NULL)
    {
        int tmp_len = strlen(tmp);
        memcpy(mac, tmp + 1, 17);
        tmp = strtok_r(NULL, ",", &saveptr);
    }
    mac_str2hex(info->bssid, mac);
    // channel
    if (tmp != NULL)
    {
        int tmp_len = strlen(tmp);
        memcpy(channel, tmp, tmp_len);
        tmp = strtok_r(NULL, ",", &saveptr);
    }
    info->frequency = ChannelToFrequency(atoi(channel));
    info->band = HOTSPOT_BAND_TYPE_2G;
}

char SendWifiCommand(char *cmd, char *args)
{
    // 清除串口接收区
    QueueClear(g_uartConfig[AT_USART_PORT-1].recvID);
    uint8_t cmd_len;
    char *send_buf;

    cmd_len = strlen(cmd);
    // 指令没有参数，可直接发送
    if (!strcmp(cmd, WIFI_RESET) || !strcmp(cmd, WIFI_GET_MODE) || !strcmp(cmd, WIFI_GET_SLEEP) ||
        !strcmp(cmd, STA_SCAN_HOTSPOT) || !strcmp(cmd, STA_EXIT_HOTSPOT) || !strcmp(cmd, STA_CURRENT_HOTSPOT) ||
        !strcmp(cmd, STA_GET_MAC) || !strcmp(cmd, STA_GET_IP) || !strcmp(cmd, SAT_AUTOLINK) ||
        !strcmp(cmd, AP_GET_MAC) || !strcmp(cmd, AP_GET_IP) || !strcmp(cmd, AP_GET_PARAM) ||
        !strcmp(cmd, AP_LIST_CLIENT) || !strcmp(cmd, STA_DISCONNECT))
    {
        send_buf = (char *)malloc(cmd_len + 2);
        if (send_buf == NULL)
            return ERROR_WIFI_UNKNOWN;
        memcpy(send_buf, cmd, cmd_len);
    }
    // 指令参数只有一个字符
    else if (!strcmp(cmd, WIFI_SET_MODE) || !strcmp(cmd, WIFI_SET_SLEEP))
    {
        send_buf = (char *)malloc(cmd_len + 1 + 2);
        if (send_buf == NULL)
            return ERROR_WIFI_UNKNOWN;
        // 复制命令
        memcpy(send_buf, cmd, cmd_len);
        // 复制参数
        send_buf[cmd_len] = *args + '0';
        // 长度加1
        cmd_len += 1;
    }
    else if (!strcmp(cmd, STA_JOIN_HOTSPOT))
    {
        // 生成ssid和密码
        char ssid[WIFI_MAX_SSID_LEN * 2 + 1] = {0};
        ESP8266_GenerateSSIDAndPassword(ssid, ((WifiDeviceConfig *)args)->ssid);
        char passwd[WIFI_MAX_KEY_LEN * 2 + 1] = {0};
        ESP8266_GenerateSSIDAndPassword(passwd, ((WifiDeviceConfig *)args)->preSharedKey);
        uint8_t ssid_len = strlen(ssid);
        uint8_t passwd_len = strlen(passwd);
        // 申请内存
        send_buf = (char *)malloc(cmd_len + ssid_len + 1 + passwd_len + 2);
        if (send_buf == NULL)
            return ERROR_WIFI_UNKNOWN;
        // 复制指令
        memcpy(send_buf, cmd, cmd_len);
        // 复制ssid
        memcpy(send_buf + cmd_len, ssid, ssid_len);
        cmd_len += ssid_len;
        // 追加逗号
        send_buf[cmd_len] = ',';
        cmd_len += 1;
        // 复制passwd
        memcpy(send_buf + cmd_len, passwd, passwd_len);
        cmd_len += passwd_len;
    }
    else if (!strcmp(cmd, STA_SCAN_HOTSPOT_CUSTOM))
    {
        // AT+CWLAP=<ssid>[,<mac>,<channel>,<scan_type>,<scan_time_min>,<scan_time_max>]
        WifiScanParams *params = (WifiScanParams *)args;
        char *ssid, *bssid;
        char ssid_len = params->ssidLen;
        // 比较参数
        switch (params->scanType)
        {
        case WIFI_FREQ_SCAN:
        case WIFI_BAND_SCAN:
            return ERROR_WIFI_NOT_SUPPORTED;
        case WIFI_SSID_SCAN:
        {
            char ssid[WIFI_MAX_SSID_LEN * 2 + 1] = {0};
            // 计算ssid
            ESP8266_GenerateSSIDAndPassword(ssid, params->ssid);
            char ssid_len = strlen(ssid);
            // 申请内存
            send_buf = (char *)malloc(cmd_len + ssid_len + 2);
            if (send_buf == NULL)
                return ERROR_WIFI_UNKNOWN;
            // 复制完整指令  AT+CWLAP="WiFi"
            memcpy(send_buf, cmd, cmd_len);
            memcpy(send_buf + cmd_len, ssid, ssid_len);
            // 长度增加
            cmd_len += ssid_len;
            break;
        }
        case WIFI_BSSID_SCAN:
        {
            char ssid[WIFI_MAX_KEY_LEN * 2 + 1] = {0};
            // --------------计算ssid--------------
            ESP8266_GenerateSSIDAndPassword(ssid, params->ssid);
            char ssid_len = strlen(ssid);
            // 申请内存
            send_buf = (char *)malloc(cmd_len + ssid_len + 1 + 19 + 2);
            if (send_buf == NULL)
                return ERROR_WIFI_UNKNOWN;
            // 复制完整指令  AT+CWLAP="WiFi"
            memcpy(send_buf, cmd, cmd_len);
            memcpy(send_buf + cmd_len, ssid, ssid_len);
            // 长度增加
            cmd_len += ssid_len;
            // ----------------bssid---------------
            bssid = (char *)malloc(20);
            if (ssid == NULL)
                return ERROR_WIFI_UNKNOWN;
            memset(bssid, 0, 20);
            bssid[0] = '\"';
            bssid[19] = '\"';
            mac_hex2str(bssid + 1, params->bssid);
            // 复制内容 AT+CWLAP="WiFi","12:34:56:78:90:12"
            send_buf[cmd_len] = ',';
            cmd_len += 1;
            memcpy(send_buf + cmd_len, bssid, 19);
            cmd_len += 19;
        }
        default:
            break;
        }
    }
    else if (!strcmp(cmd, STA_SET_MAC))
    {
    }
    else if (!strcmp(cmd, STA_SET_IP))
    {
    }
    else if (!strcmp(cmd, STA_CONNECT))
    {
        // AT+CIPSTART="TCP","192.168.101.110",8000
        uint8_t tmp[256]={0};
        memcpy(tmp, cmd, cmd_len);
        tmp[cmd_len] = '\"';
        cmd_len += 1;
        if(((ServerInfo *)args)->protocol == TCP)
        memcpy(tmp+cmd_len, "TCP", 3);
        else if(((ServerInfo *)args)->protocol == UDP)
        memcpy(tmp+cmd_len, "UDP", 3);
        cmd_len += 3;
        tmp[cmd_len] = '\"';
        cmd_len += 1;
        tmp[cmd_len] = ',';
        cmd_len += 1;
        tmp[cmd_len] = '\"';
        cmd_len += 1;
        memcpy(tmp+cmd_len, ((ServerInfo *)args)->serverIP, strlen(((ServerInfo *)args)->serverIP));
        cmd_len += strlen(((ServerInfo *)args)->serverIP);
        tmp[cmd_len] = '\"';
        cmd_len += 1;
        tmp[cmd_len] = ',';
        cmd_len += 1;
        uint8_t port[6]={0};
        sprintf(port, "%u", ((ServerInfo *)args)->port);
        memcpy(tmp+cmd_len, port, strlen(port));
        cmd_len += strlen(port);
        send_buf = (char *)malloc(cmd_len+2);
        if (send_buf == NULL)
            return ERROR_WIFI_UNKNOWN;
        memcpy(send_buf, tmp, cmd_len);
    }
    else if (!strcmp(cmd, STA_SEND))
    {
        // AT+CIPSEND=<length>
        // 申请内存
        send_buf = (char *)malloc(cmd_len + strlen(args) + 2);
        if (send_buf == NULL)
            return ERROR_WIFI_UNKNOWN;
        // 复制数据
        memcpy(send_buf, cmd, strlen(cmd));
        memcpy(send_buf + cmd_len, args, strlen(args));
        cmd_len += strlen(args);
    }
    else if (!strcmp(cmd, AP_SET_MAC))
    {
    }
    else if (!strcmp(cmd, AP_SET_IP))
    {
    }
    else if (!strcmp(cmd, AP_SET_PARAM))
    {
        if (args == NULL)
            return -2;
        // AT+CWSAP_DEF=<ssid>,<pwd>,<chl>,<ecn>[,<max conn>][,<ssid hidden>]
        // 密码
        char passwd[WIFI_MAX_KEY_LEN] = {0};
        HotspotConfig *config = (HotspotConfig *)args;
        memcpy(passwd, config->preSharedKey, strlen(config->preSharedKey));
        config->securityType;
        // ssid
        char ssid[WIFI_MAX_SSID_LEN] = {0};
        memcpy(ssid, config->ssid, strlen(config->ssid));
        // 加密方式
        char ecn = -1;
        switch (config->securityType)
        {
        case WIFI_SEC_TYPE_OPEN:
            ecn = '0';
            break;
        case WIFI_SEC_TYPE_WEP:
            return ERROR_WIFI_NOT_SUPPORTED;
        case WIFI_SEC_TYPE_PSK:
            ecn = '2';
            break;
        case WIFI_SEC_TYPE_SAE:
            return ERROR_WIFI_NOT_SUPPORTED;
        }
        // 生成ESP8266需要的ssid和passwd
        char cmd_ssid[WIFI_MAX_KEY_LEN * 2 + 1] = {0};
        char cmd_passwd[WIFI_MAX_SSID_LEN * 2 + 1] = {0};
        ESP8266_GenerateSSIDAndPassword(cmd_ssid, ssid);
        ESP8266_GenerateSSIDAndPassword(cmd_passwd, passwd);
        // 计算长度
        uint8_t ssid_len = strlen(ssid);
        uint8_t pass_len = strlen(passwd);
        // 信道
        char cmd_ch[4] = {0};
        sprintf(cmd_ch, "%d", config->channelNum);
        uint8_t ch_len = strlen(cmd_ch);
        // 命令长度  AT+CWSAP_CUR="ESP8266","12345678",5,3
        // cmd_len = pre_len + ssid_len + 1 + pass_len + 1 + ch_len + 1 + 1;
        send_buf = (char *)malloc(cmd_len + ssid_len + 1 + pass_len + 1 + ch_len + 1 + 1 + 2);
        if (send_buf == NULL)
            return ERROR_WIFI_UNKNOWN;
        // 复制命令头
        memcpy(send_buf, cmd, cmd_len);
        // 复制ssid
        memcpy(send_buf + cmd_len, cmd_ssid, ssid_len);
        cmd_len += ssid_len;
        // 追加逗号
        send_buf[cmd_len] = ',';
        cmd_len += 1;
        // 复制Passwd
        memcpy(send_buf + cmd_len, cmd_passwd, pass_len);
        cmd_len += pass_len;
        // 追加逗号
        send_buf[cmd_len] = ',';
        cmd_len += 1;
        // 复制信道
        memcpy(send_buf + cmd_len, cmd_ch, ch_len);
        cmd_len += ch_len;
        // 追加逗号
        send_buf[cmd_len] = ',';
        cmd_len += 1;
        send_buf[cmd_len] = ecn;
    }
    else if (!strcmp(cmd, AP_SET_DHCP))
    {
    }

    // 增加尾部
    memcpy(send_buf + cmd_len, "\r\n", 2);
    cmd_len += 2;
    // 发送指令
    int res = IoTUartWrite(AT_USART_PORT, send_buf, cmd_len);
    // 释放内存
    free(send_buf);
    // 没发送完毕
    if (res != cmd_len)
        return ERROR_WIFI_UNKNOWN;
    return WIFI_SUCCESS;
}

int8_t WaitWifiResponse(char *cmd, char *result, uint32_t timeout)
{
    memset(rsp_buf, 0, 1024);
    delay_ms(2000);
    int8_t res;
    uint32_t rsp_len = 0;
    uint32_t wifi_delay=0;
    // 循环读取，直到OK\FAIL\ERROR，或则超时就退出
    while (strstr(rsp_buf, "\r\nOK\r\n") == NULL && strstr(rsp_buf, "\r\nFAIL\r\n") == NULL && strstr(rsp_buf, "\r\nERROR\r\n") == NULL && strstr(rsp_buf, "ready") == NULL)
    {
        uint32_t cur_len;
        // 当前队列长度
        cur_len = g_queueInfo[g_uartConfig[AT_USART_PORT-1].recvID].cur_len;
        // 读取队列
        IoTUartRead(AT_USART_PORT, &rsp_buf[rsp_len], cur_len);
        // 总长度增加  
        rsp_len += cur_len;
        // 超时则退出
        if (wifi_delay++ > timeout)
        {   
            res = ERROR_WIFI_UNKNOWN;
            break;
        }
        delay_ms(1000);
    }
    
    // printf("rsp:%s\n", rsp_buf);
    // 打开回显功能，每次应答都包含当前cmd
    if (strstr(rsp_buf, cmd) == NULL)
        return ERROR_WIFI_UNKNOWN;
    // 错误的指令
    if (strstr(rsp_buf, "\r\nERROR\r\n") != NULL)
        return ERROR_WIFI_INVALID_ARGS;
    // 开始解析正确的应答
    if(!strcmp(cmd, WIFI_RESET))
    {
        if (strstr(rsp_buf, "\r\nOK\r\n"))
            res = WIFI_SUCCESS;
        else
            res = ERROR_WIFI_UNKNOWN;
    }
    else if (!strcmp(cmd, WIFI_SET_MODE))
    {
        // "AT+CWMODE=1\r\n\r\nOK\r\n"

        // 无效参数
        if (result == NULL)
            return ERROR_WIFI_INVALID_ARGS;
        else
        {
            *result = rsp_buf[10];
            res = WIFI_SUCCESS;
        }
    }
    else if (!strcmp(cmd, STA_SCAN_HOTSPOT) || !strcmp(cmd, STA_SCAN_HOTSPOT_CUSTOM))
    {
        // AT+CWLAP\r\n
        // +CWLAP:(4,"Xiaomi_9F9E",-80,"f0:b4:29:e2:9f:9f",1,-7,0)\r\n
        // +CWLAP:(4,"DoMyNet_301",-89,"c8:5b:a0:ca:05:fe",1,-39,0)\r\n
        // \r\nOK\r\n
        if (strstr(rsp_buf, "\r\nOK\r\n"))
        {
            res = WIFI_SUCCESS;
            char *tmp, *saveptr;
            // 分割字符串
            //tmp = strtok(rsp_buf, "\r\n"); 这个函数不安全，引起堆栈内存不足死机
            tmp = strtok_r(rsp_buf, "\r\n", &saveptr);
            while (tmp != NULL)
            {
                // 热点信息加入对队列
                if (strstr(tmp, "+CWLAP:("))
                {
                    QueueIn(g_scanQueue, tmp + 8);
                }
                tmp = strtok_r(NULL, "\r\n", &saveptr);
            }
        }
        else
        {
            res = ERROR_WIFI_UNKNOWN;
        }
    }
    else if (!strcmp(cmd, STA_JOIN_HOTSPOT))
    {
        // AT+CWJAP_DEF="Mate 30 Pro 5G","123321123"\r\n
        // WIFI CONNECTED\r\n
        // WIFI GOT IP\r\n
        // \r\nOK\r\n

        // AT+CWJAP_DEF="Mate 30 Pro 5G","123321123"\r\n
        // +CWJAP:3\r\n
        // \r\nFAIL\r\n

        // AT+CWJAP_DEF="Mate 30 Pro 5G","123321123"\r\n
        // +CWJAP_DEF:3\r\n
        // \r\nERROR\r\n
        // 成功
        if (strstr(rsp_buf, "\r\nOK\r\n"))
        {
            res = WIFI_SUCCESS;
        }
        // 失败
        else if (strstr(rsp_buf, "\r\nFAIL\r\n"))
        {
            // 取+CWJAP:部分
            char *tmp = strstr(rsp_buf, "+CWJAP_DEF:");
            if (tmp != NULL)
            {
                // 分析失败原因
                switch (tmp[11])
                {
                case '1':
                    res = ERROR_WIFI_BUSY;
                    break; // 超时
                case '2':
                    res = ERROR_WIFI_INVALID_PASSWORD;
                    break; // 密码错误
                case '3':
                    res = ERROR_WIFI_NOT_AVAILABLE;
                    break; // 找不到AP
                case '4':
                    res = ERROR_WIFI_UNKNOWN;
                    break; // 连接失败
                default:
                    res = ERROR_WIFI_UNKNOWN;
                    break;
                }
            }
        }
        else if (strstr(rsp_buf, "\r\nERROR\r\n"))
        {
            // wifi没有启动
            res = ERROR_WIFI_NOT_STARTED;
        }
    }
    else if (!strcmp(cmd, STA_EXIT_HOTSPOT))
    {
        // AT+CWQAP\r\n
        // \r\nOK\r\n
        // WIFI DISCONNECT\r\n
        res = WIFI_SUCCESS;
    }
    else if (!strcmp(cmd, STA_CURRENT_HOTSPOT))
    {
        // AT+CWJAP_CUR?\r\n
        // +CWJAP_CUR:"Mate 30 Pro 5G","1a:56:21:fe:c7:31",1,-63, 0\r\n
        // \r\nOK\r\n

        // AT+CWJAP_CUR?\r\n
        // No AP\r\n
        // \r\nOK\r\n

        if (result == NULL)
            return ERROR_WIFI_INVALID_ARGS;
        // 找到热点信息出现的位置, 取+CWJAP:部分
        char *tmp, *saveptr;
        tmp = strstr(rsp_buf, "+CWJAP:");
        if (tmp != NULL)
        {
            // 分割字符串，将热点信息回传
            tmp = strtok_r(tmp, "\r\n", &saveptr);
            // 解析 +CWJAP_CUR:"Mate 30 Pro 5G","1a:56:21:fe:c7:31",1,-63
            char *tmp_res, bssid[18] = {0}, channel[4] = {0}, rssi[5] = {0};
            // 以逗号进行分割
            // ssid
            tmp_res = strtok_r(&tmp[11], ",", &saveptr);
            memcpy(((WifiLinkedInfo *)result)->ssid, tmp_res + 1, strlen(tmp_res) - 2);
            // bssid, 需要进行字符串转十六进制
            tmp_res = strtok_r(NULL, ",", &saveptr);
            memcpy(bssid, tmp_res + 1, strlen(tmp_res) - 2);
            mac_str2hex(((WifiLinkedInfo *)result)->band, bssid);
            // channel
            tmp_res = strtok_r(NULL, ",", &saveptr);
            memcpy(channel, tmp_res, strlen(tmp_res));
            // rssi
            tmp_res = strtok_r(NULL, ",", &saveptr);
            memcpy(rssi, tmp_res, strlen(tmp_res));
            ((WifiLinkedInfo *)result)->rssi = atoi(rssi);
            res = WIFI_SUCCESS;
        }
        // 无热点链接
        else if (strstr(rsp_buf, "No AP"))
        {
            res = ERROR_WIFI_NOT_AVAILABLE;
        }
        else
            res = ERROR_WIFI_UNKNOWN;
    }
    else if (!strcmp(cmd, STA_GET_IP))
    {
        // AT+CIPSTA?\r\n
        // +CIPSTA:ip:"192.168.43.90"\r\n
        // +CIPSTA:gateway:"192.168.43.1"\r\n
        // +CIPSTA:netmask:"255.255.255.0"\r\n
        // \r\nOK\r\n

        // AT+CIPSTA?\r\n
        // +CIPSTA:ip:"0.0.0.0"\r\n
        // +CIPSTA:gateway:"0.0.0.0"\r\n
        // +CIPSTA:netmask:"0.0.0.0"\r\n
        // \r\nOK\r\n
        if (result == NULL)
            return ERROR_WIFI_INVALID_ARGS;
        // 分割字符串，去掉头部
        char *tmp, *saveptr;
        tmp = strtok_r(rsp_buf, "\r\n", &saveptr);
        uint8_t tmp_len;
        uint8_t tmp_info[36] = {0};
        // +CIPSTA:ip:"192.168.43.90"
        tmp = strtok_r(NULL, "\r\n", &saveptr);
        tmp_len = strlen(tmp);
        memcpy(tmp_info, tmp + 12, tmp_len - 12 - 1);
        ((IpInfo *)result)->ipAddress = ip_to_int(tmp_info);
        // +CIPSTA:gateway:"0.0.0.0"
        tmp = strtok_r(NULL, "\r\n", &saveptr);
        tmp_len = strlen(tmp);
        memset(tmp_info, 0, 36);
        memcpy(tmp_info, tmp + 17, tmp_len - 17 - 1);
        ((IpInfo *)result)->netGate = ip_to_int(tmp_info);
        // +CIPSTA:netmask:"0.0.0.0"\r\n
        tmp = strtok_r(NULL, "\r\n", &saveptr);
        tmp_len = strlen(tmp);
        memset(tmp_info, 0, 36);
        memcpy(tmp_info, tmp + 17, tmp_len - 17 - 1);
        ((IpInfo *)result)->netMask = ip_to_int(tmp_info);

        res = WIFI_SUCCESS;
    }
    else if (!strcmp(cmd, STA_GET_MAC))
    {
        // AT+CIPSTAMAC?\r\n
        // +CIPSTAMAC:"5c:cf:7f:14:1b:2b"\r\n
        // \r\nOK\r\n

        if (result == NULL)
            return ERROR_WIFI_IFACE_INVALID;
        // 取mac地址信息部分
        char *tmp, *saveptr;
        tmp = strstr(rsp_buf, "+CIPSTAMAC:");
        // 去掉结尾OK
        tmp = strtok_r(tmp, "\r\n", &saveptr);
        char mac[18] = {0};
        memcpy(mac, tmp + 12, 17);
        mac_str2hex(result, mac);
        res = WIFI_SUCCESS;
    }
    else if (!strcmp(cmd, STA_CONNECT))
    {
        // AT+CIPSTART="TCP","192.168.43.131",6000\r\n
        // CONNECT\r\n
        // \r\nOK\r\n

        // AT+CIPSTART="TCP","192.168.43.131",6000\r\n
        // ALREADY CONNECTED\r\n
        // \r\nERROR\r\n

        // AT+CIPSTART="TCP","192.168.43.131",6001\r\n
        // \r\nERROR\r\n
        // CLOSED\r\n
        if(strstr(rsp_buf, "\r\nOK\r\n") || strstr(rsp_buf, "ALREADY CONNECTED\r\n"))
        {
            return WIFI_SUCCESS;
        }
        else
        {
            return ERROR_WIFI_INVALID_ARGS;
        }
    }
    else if (!strcmp(cmd, STA_DISCONNECT))
    {
        // AT+CIPCLOSE\r\n
        // CLOSED\r\n
        // \r\nOK\r\n
        return WIFI_SUCCESS;
    }
    else if (!strcmp(cmd, STA_SEND))
    {
        // AT+CIPSEND=10\r\n
        // \r\nOK\r\n
        // >空格 

        // \r\nRecv 10 bytes\r\n
        // \r\nSEND OK\r\n
        if(strstr(rsp_buf, "\r\nOK\r\n"))
        {
            return WIFI_SUCCESS;
        }
    }
    else if (!strcmp(cmd, AP_GET_PARAM))
    {
        // AT+CWSAP_CUR?\r\n
        // +CWSAP_CUR:"ESP_141B2B","",1,0,4,0\r\n
        // \r\nOK\r\n

        // AT+CWSAP_CUR?\r\n
        // \r\nERROR\r\n

        if (result == NULL)
            return ERROR_WIFI_INVALID_ARGS;
        if (strstr(rsp_buf, "\r\nOK\r\n"))
        {
            res = WIFI_SUCCESS;
            // 解析 +CWSAP_DEF:"ESP_141B2B","",1,0,4,0
            char *tmp, *saveptr;
            tmp = strtok_r(rsp_buf, "\r\n", &saveptr);
            tmp = strtok_r(NULL, "\r\n", &saveptr);
            // ssid
            memcpy(((HotspotConfig *)result)->ssid, tmp + 12, strlen(tmp) - 12 - 1);
            // passwd
            tmp = strtok_r(NULL, ",", &saveptr);
            memcpy(((HotspotConfig *)result)->preSharedKey, tmp + 1, strlen(tmp) - 2);
            // channel
            tmp = strtok_r(NULL, ",", &saveptr);
            ((HotspotConfig *)result)->channelNum = atoi(tmp);
            // psktype
            tmp = strtok_r(NULL, ",", &saveptr);
            switch (tmp[0])
            {
            case '0':
                ((HotspotConfig *)result)->securityType = WIFI_SEC_TYPE_OPEN;
                break;
            case '1':
                ((HotspotConfig *)result)->securityType = WIFI_SEC_TYPE_WEP;
                break;
            case '2':
            case '3':
            case '4':
                ((HotspotConfig *)result)->securityType = WIFI_SEC_TYPE_PSK;
                break;
            default:
                break;
            }
            ((HotspotConfig *)result)->band = HOTSPOT_BAND_TYPE_2G;
        }
        else
            res = ERROR_WIFI_UNKNOWN;
    }
    else if (!strcmp(cmd, AP_SET_PARAM))
    {
        // AT+CWSAP_CUR="ESP8266","12345678",5,3\r\n
        // \r\nOK\r\n

        // AT+CWSAP_CUR="ESP8266","12345678",5,3\r\n
        // \r\nERROR\r\n
        if (strstr(rsp_buf, "\r\nOK\r\n"))
            res = WIFI_SUCCESS;
        else
            res = ERROR_WIFI_UNKNOWN;
    }
    else if (!strcmp(cmd, AP_LIST_CLIENT))
    {
        // AT+CWLIF\r\n
        // 192.168.4.2,02:7d:81:bb:6d:63\r\n
        // 192.168.4.3,98:01:a7:9f:5e:9d\r\n
        // \r\nOK\r\n

        // AT+CWLIF\r\n
        // \r\nOK\r\n

        // AT+CWLIF\r\n
        // \r\nERROR\r\n
        if (strstr(rsp_buf, "\r\nOK\r\n") && strlen(rsp_buf) > 16 && g_clientQueue != -1)
        {
            res = WIFI_SUCCESS;
            if (strlen(rsp_buf) > 16)
            {
                res = WIFI_SUCCESS;
                // 去除尾部
                char *tmp, *saveptr;
                tmp = strtok_r(rsp_buf, "\r\nOK\r\n", &saveptr);
                // 跟个字符串，第一个丢弃
                tmp = strtok_r(tmp, "\r\n", &saveptr);
                // 下一个开始循环保存
                tmp = strtok_r(tmp, "\r\n", &saveptr);
                while (tmp != NULL)
                {
                    QueueIn(g_clientQueue, tmp);
                    tmp = strtok_r(NULL, "\r\n", &saveptr);
                }
            }
        }
        else
            res = ERROR_WIFI_UNKNOWN;
    }
    // WIFI DISCONNECT
    return res;
}

uint8_t ESP8266_ConnectTo(char *ip, uint16_t port, ProtocolType type)
{
    WifiErrorCode res;
    ServerInfo info={0};
    // 复制信息
    memcpy(info.serverIP, ip, strlen(ip));
    info.protocol = type;
    info.port = port;
    // 发送指令
    res = SendWifiCommand(STA_CONNECT, &info);
    if(res == WIFI_SUCCESS)
    {
        res = WaitWifiResponse(STA_CONNECT, NULL, WIFI_TIMEOUT);
    }
	if(res == WIFI_SUCCESS)
	{
		printf("Connect to Server %s OK\n", ip);
	}
    return res;
}

uint8_t ESP8266_DisConnect()
{
    WifiErrorCode res;
    // 发送指令
    res = SendWifiCommand(STA_DISCONNECT, NULL);
    if(res == WIFI_SUCCESS)
    {
        res = WaitWifiResponse(STA_DISCONNECT, NULL, WIFI_TIMEOUT);
    }
    return res;
}

int ESP8266_Send(char *msg, int msglen)
{
    int res;
    uint8_t len[7]={0};
    sprintf(len, "%d", msglen);
    // 发送指令
    res = SendWifiCommand(STA_SEND, len);
    if(res == WIFI_SUCCESS)
    {
        // 等待应答
        res = WaitWifiResponse(STA_SEND, NULL, WIFI_TIMEOUT);
        if(res == WIFI_SUCCESS)
        {
            // 发送数据
            res = IoTUartWrite(AT_USART_PORT, msg, msglen);
        }
    }
    return res;
}

// 由于串口收到的数据是 +IPD,3:123 类型，因此需要将数据解析到另一个队列中
int ESP8266_Recv(char *recvBuf, int recvLen, uint32_t timeout)
{
    int res;
    // 参数检测
    if(recvBuf==NULL)
        return ERROR_WIFI_UNKNOWN;
    // 创建队列
    if(g_ESP8266_MsgQueue == 0xff)
    {
        if(QueueCreate(&g_ESP8266_MsgQueue, 1, 4096)!=SUCCESS)
            return FAILED;
    }
    uint16_t wifi_delay=0;
    uint32_t cur_len=0;
    // 持续获取数据
    while(1)
    {
        // 当前串口队列长度
        cur_len = g_queueInfo[g_uartConfig[AT_USART_PORT-1].recvID].cur_len;
		if(cur_len>0)
		{
			char *tmp_buf = (char *)malloc(cur_len);
			if(tmp_buf == NULL)
			{
				return ERROR_WIFI_UNKNOWN;
			}
			// 读取队列
			IoTUartRead(AT_USART_PORT, tmp_buf, cur_len);
			// +IPD,3:123
			char *tmp, tmp_len[7]={0};
			tmp = strstr(tmp_buf, "+IPD,");
			while(tmp != NULL)
			{
				// 找到冒号
				uint16_t pos;
				for(pos=0; ;pos++)
				{
					if(tmp[pos]==':')
						break;
				}
				// 提取长度
				memcpy(tmp_len, tmp+5, pos-5);
				// 长度后面的数据入队
				for(uint16_t i=0; i<atoi(tmp_len); i++,pos++)
				{
					// 入队
					QueueIn(g_ESP8266_MsgQueue, &tmp[pos+1]);
				}
				// 继续查找下一个
				tmp = strstr(tmp+pos, "+IPD,");
			}
			// 释放内存
			free(tmp_buf);
		}
		// 数据长度满足
		if(g_queueInfo[g_ESP8266_MsgQueue].cur_len >= recvLen)
		{
			break;
		}
        // 超时
		if(wifi_delay++ > WIFI_TIMEOUT)
			break;
		delay_ms(1000);
    }
    // 数据出队
    res = g_queueInfo[g_ESP8266_MsgQueue].cur_len<recvLen?g_queueInfo[g_ESP8266_MsgQueue].cur_len:recvLen;
    for(uint16_t i=0; i<res; i++)
    {
        QueueOut(g_ESP8266_MsgQueue, &recvBuf[i]);
    }
    return res;
}